package com.wutma.system.service.sysuser.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wutma.common.core.constants.HttpConstants;
import com.wutma.common.core.domain.R;
import com.wutma.common.core.domain.entity.LoginUser;
import com.wutma.common.core.domain.vo.LoginUserVO;
import com.wutma.common.core.enums.ResultCode;
import com.wutma.common.core.enums.UserIdentity;
import com.wutma.common.security.exception.ServiceException;
import com.wutma.common.security.service.TokenService;
import com.wutma.system.domain.sysuser.dto.LoginDTO;
import com.wutma.system.domain.sysuser.entity.SysUser;
import com.wutma.system.domain.sysuser.dto.SysUserSaveDTO;
import com.wutma.system.mapper.sysuser.SysUserMapper;
import com.wutma.system.service.sysuser.SysUserService;
import com.wutma.system.utils.BCryptUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import java.util.List;

import static com.wutma.common.core.enums.ResultCode.FAILED_LOGIN;
import static com.wutma.common.core.enums.ResultCode.FAILED_USER_NOT_EXISTS;

@Service
@Slf4j
@RefreshScope
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Value("${jwt.secret}")
    private String secrete;

    @Autowired
    private TokenService tokenService;

    @Override
    public R<String> login(LoginDTO loginDTO) {

        // 1. 在数据库中判断用户是否存在
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        SysUser sysUser = sysUserMapper.selectOne(
                queryWrapper.select(SysUser::getUserId, SysUser::getPassword, SysUser::getNickName)
                        .eq(SysUser::getUserAccount, loginDTO.getUserAccount()));
        if (sysUser == null) {
            // 用户不存在
            return R.fail(FAILED_USER_NOT_EXISTS);
        }
        // 2. 判断用户输入密码是否正确
        if (!BCryptUtils.matchesPassword(loginDTO.getPassword(), sysUser.getPassword())) {
            // 密码错误
            return R.fail(FAILED_LOGIN);
        }
        // 3. 验证通过，创建token并返回
        String token = tokenService.createToken(sysUser.getUserId(), secrete, UserIdentity.ADMIN.getValue(), sysUser.getNickName(), null);
        return R.ok(token);
    }

    @Override
    public int add(SysUserSaveDTO sysUserSaveDTO) {

        List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUserAccount, sysUserSaveDTO.getUserAccount()));
        if (CollectionUtil.isNotEmpty(sysUsers)) {
            // 用户已经存在
            throw new ServiceException(ResultCode.AILED_USER_EXISTS);
        }
        SysUser sysUser = new SysUser();
        sysUser.setUserAccount(sysUserSaveDTO.getUserAccount());
        sysUser.setPassword(BCryptUtils.encryptPassword(sysUserSaveDTO.getPassword()));
        return sysUserMapper.insert(sysUser);
    }

    @Override
    public R<LoginUserVO> info(String token) {

        token = getNormalToken(token);
        LoginUser loginUser = tokenService.getLoginUser(token, secrete);
        if (loginUser == null) {
            return R.fail();
        }
        LoginUserVO loginUserVO = new LoginUserVO();
        loginUserVO.setNickName(loginUser.getNickName());
        return R.ok(loginUserVO);
    }

    @Override
    public boolean logout(String token) {
        token = getNormalToken(token);
        return tokenService.deleteLoginUser(token, secrete);
    }

    private String getNormalToken(String token) {
        // 去掉令牌Bearer前缀
        if (StrUtil.isNotEmpty(token) && token.startsWith(HttpConstants.PREFIX)) {
            token = token.replaceFirst(HttpConstants.PREFIX, StrUtil.EMPTY);
        }
        return token;
    }
}
